//
//  NetTool.swift
//  LeMessage
//
//  Created by Rowling on 2020/3/9.
//  Copyright © 2020 Rowling. All rights reserved.
//

import Foundation
import Alamofire
import HandyJSON
import SwiftyJSON
typealias resp<T> = (_ resp : ResponseModel<T>)->()

struct ResponseModel<T> : HandyJSON {
    var message = "加载失败，请稍后尝试"
    var data : T?
    var code : ModelCode = ModelCode.netBad
    var sysTime : TimeInterval = 0
    var realResp : Any?
    
    mutating func mapping(mapper: HelpingMapper) {
        mapper <<<
            self.code <-- TransformOf<ModelCode, Int>(fromJSON: { (num) -> ModelCode? in
                if let num = num {
                    switch (num) {
                    case 0:
                        return ModelCode.success
                    case 200:
                        return ModelCode.success
                    default:
                        return ModelCode.init(rawValue: num)
                    }
                }
                return ModelCode.netBad
            }, toJSON: { (theCode) -> Int? in
                if let theCode = theCode {
                    return theCode.rawValue
                }
                return -1
            })
    }
}

enum ModelCode: Int, HandyJSONEnum {
    case success = 200
    case netBad = -1
    case missionInvalid = 1
    case invalidToken = 401
    case repetitionRequest = 900
    case auctionFreshMan  = 600
    case showToast = 800
//    case needCodeBindDevice = 10
    
    func description() -> String {
        switch self {
        case .success: return "成功"
        case .netBad: return "加载失败，请稍后尝试"
        case .missionInvalid : return "任务已完成"
        case .invalidToken : return "token失效"
        case .repetitionRequest : return "重复请求"
        case .auctionFreshMan : return "新人场不行"
        case .showToast: return ""
        }
    }
}

enum ZMNetStatus {
    /**未知网络*/
    case unkown
    /**无网络*/
    case notReachable
    /**wifi*/
    case WIFI
    /**蜂窝*/
    case WWAN
}

class ZMNetManager {
    static let shared = ZMNetManager()
    var apiprovider : ZMApiProvider?
    /**网络监听管理类*/
    private let netAbility = NetworkReachabilityManager(host: "www.baidu.com")
    /**网络状态监听*/
    let netStauts = ReplaySubject<ZMNetStatus>.create(bufferSize: 1)
    
//    static let sharedSessionManager: Alamofire.SessionManager = {
//        let configuration = URLSessionConfiguration.default
//        configuration.timeoutIntervalForRequest = 15
//        return Alamofire.SessionManager(configuration: configuration)
//    }()
    
    func badResponse<T>(realResp : Any?,message:String) -> ResponseModel<T> {
        var r = ResponseModel<T>()
        r.message = message
        r.realResp = realResp
        r.code = .netBad
        return r
    }
    
    func getJSONStringFromDictionary(dictionary:NSDictionary) -> String {
        if (!JSONSerialization.isValidJSONObject(dictionary)) {
            XMLogger.netInfo("无法解析出JSONString")
            return ""
        }
        let data : NSData! = try? JSONSerialization.data(withJSONObject: dictionary, options: []) as NSData?
        let JSONString = NSString(data:data as Data,encoding: String.Encoding.utf8.rawValue)
        return JSONString! as String
    }
    
    func Request<T>(url : String ,
                    Method : HTTPMethod ,
                    param : [String : Any] ,
                    httpHeaders : HTTPHeaders?,
                    rawData : Bool = false,
                    callBack :@escaping resp<T>) -> DataRequest? {
        
        guard let wholeUrl = URL(string:url) else {
            return nil
        }
        
        XMLogger.netInfo("请求地址：------->\(wholeUrl)\n请求参数:")
        for (str,vaule) in param {
            XMLogger.netInfo("\(str):\(vaule)")
        }
        XMLogger.netInfo("header:\n")
        var headers : HTTPHeaders = [
        "Content-Type": "application/json;charset=UTF-8",
        "Accept": "application/json",
        ]
        if let httpHeaders = httpHeaders {
            headers = httpHeaders
        }
        XMLogger.netInfo(headers)
        
        var encoding : ParameterEncoding = URLEncoding.queryString
        if (headers["Content-Type"] ?? "").contains("application/json") {
            encoding = JSONEncoding.default
        }
        
        if let arrayPa = param["ZMArrayParams"] as? [[String : Any]] {
            // 参数是数组的请求
            return arrayParamRequest(url: wholeUrl, Method: Method, param: arrayPa, httpHeaders: headers, rawData: rawData, callBack: callBack)
        }
    
        let r = AF.request(wholeUrl, method: Method, parameters: param, encoding: encoding, headers: headers, requestModifier: { $0.timeoutInterval = 30}).response { response in
            if let resp = response.response {
               let code = resp.statusCode
//                if code != 200 {
//                    XMLogger.netInfo("请求外层报错")
//                    callBack(self.badResponse(realResp: "网络错误-code:\(code)", message: "\(url)\n" + "网络错误-code:\(code)"))
//                    return
//                }
                let data = response.result
                    switch data {
                    case .success(let data):
                        if let okData = data {
                        do {
                                guard let dict = try JSONSerialization.jsonObject(with: okData,options: .allowFragments) as? [String : Any] else {
                                    callBack(ResponseModel())
                                    return}

                            let j = JSON(dict)
                            XMLogger.netInfo("请求结果：------->\(String(describing: wholeUrl))\n")
                            XMLogger.netInfo(j)
                                if rawData {
                                    var rs = ResponseModel<T>()
                                    if let dict = dict as? T {
                                        rs.code = .success
                                        rs.data = dict
                                    } else {
                                        rs.code = .netBad
                                        rs.message = "App解析出错"
                                    }
                                    rs.realResp = dict
                                    callBack(rs)
                                } else {
                                    guard var data = JSONDeserializer<ResponseModel<T>>.deserializeFrom(dict: dict) else {
                                        var rs = ResponseModel<T>()
                                        rs.code = .netBad
                                        rs.message = "App解析出错"
                                        rs.realResp = dict
                                        callBack(rs)
                                        return}
                                    data.realResp = dict
                                    callBack(data)
                                }
                        } catch {
                            if let s = String.init(data: okData, encoding: .utf8) {
                                XMLogger.netInfo(s)
//                                    let web = UIWebView()
//                                    web.loadHTMLString(s, baseURL: nil)
//                                    APPWindow?.addSubview(web)
//                                    web.snp.makeConstraints { make in
//                                        make.edges.equalToSuperview()
//                                    }
                                callBack(self.badResponse(realResp: s, message: "\(url)\nhttp-code:\(code)\n\(s))"))
                            } else {
                                callBack(self.badResponse(realResp: "json 解析异常", message: "\(url)\njson 解析异常"))
                            }
                        }
                    } else {
                            
                    }
                    case .failure(let error):
                        XMLogger.netInfo("请求结果：------->\(String(describing: wholeUrl))\n")
                        XMLogger.netInfo(error)
                        callBack(self.badResponse(realResp: error.errorDescription, message: "\(url)\n" + (error.errorDescription ?? "")))
                        break
                    
                    }
            } else if let error = response.error {
                callBack(self.badResponse(realResp: error.errorDescription, message: "\(url)\n" + (error.errorDescription ?? "")))
            }
        }
            return r
    }
    
    func arrayParamRequest<T>(url : URL ,
                              Method : HTTPMethod ,
                              param : [[String : Any]] ,
                              httpHeaders : HTTPHeaders?,
                              rawData : Bool = false,
                              callBack :@escaping resp<T>) -> DataRequest? {
        // 数组参数
        do {
            
            var request = try URLRequest(url: url, method: Method, headers: httpHeaders)
            let data = try JSONSerialization.data(withJSONObject: param, options: [])
            request.httpBody = data
            let r = AF.request(request as URLRequestConvertible).responseJSON { response in
                switch response.result {
                    case .success(let vaule):
                        guard let dict = vaule as? Dictionary<String, Any> else {
                            callBack(ResponseModel())
                            return}
                        let j = JSON(dict)
                    XMLogger.netInfo("请求结果：------->\(String(describing: url))\n")
                    XMLogger.netInfo(j)
                        if rawData {
                            var rs = ResponseModel<T>()
                            if let dict = dict as? T {
                                rs.code = .success
                                rs.data = dict
                            } else {
                                rs.code = .netBad
                                rs.message = "App解析出错"
                            }
                            rs.realResp = dict
                            callBack(rs)
                        } else {
                            guard var data = JSONDeserializer<ResponseModel<T>>.deserializeFrom(dict: dict) else {
                                var rs = ResponseModel<T>()
                                rs.code = .netBad
                                rs.message = "App解析出错"
                                rs.realResp = dict
                                callBack(rs)
                                return}
                            data.realResp = dict
                            callBack(data)
                        }
                        break
                    case .failure(let error):
                    XMLogger.netInfo("请求结果：------->\(String(describing: url))\n")
                    XMLogger.netInfo(error)
                        callBack(self.badResponse(realResp: error.errorDescription, message: error.errorDescription ?? ""))
                        break
                }
            }
            return r
        }
        catch {
            return nil
        }
    }
    
    func requestUpload<T>(url : String , data: [Data],httpHeaders : HTTPHeaders?, callBack: @escaping resp<T>) -> UploadRequest?{
       let request = requestFileUpload(url: url, mimeType: "image/png", paramName: "picture", files: [(String, Data)](), httpHeaders: httpHeaders,multipartFormData:{ multipartFormData in
            for i in 0..<data.count{
                //设置图片的名字
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyyMMddHHmmss"
                let string = formatter.string(from: Date())
                let filename = "\(string).png"
                multipartFormData.append(data[i], withName: "multipart", fileName: filename, mimeType: "image/png")
            }
        }, callBack: callBack)
        return request
    }
    
    func requestFileUpload<T>(url : String ,mimeType : String ,paramName : String , files:[(String,Data)] ,httpHeaders : HTTPHeaders?,multipartFormData : ((MultipartFormData) -> Void)? = nil, callBack: @escaping resp<T>) -> UploadRequest? {
        
        var headers : HTTPHeaders = [
            "Content-Type": "multipart/form-data",
            "Accept": "application/json",
            ]
        if let httpHeaders = httpHeaders {
            headers = httpHeaders
        }
        
        guard let wholeUrl = URL(string:url) else {
            return nil
        }

        let reqest = AF.upload(multipartFormData: multipartFormData ?? { multipartFormData in
            for data in files{
                //设置图片的名字
                multipartFormData.append(data.1, withName: paramName, fileName: data.0, mimeType: mimeType)
            }
        }, to: wholeUrl,method: HTTPMethod.post, headers: headers).responseJSON { encodingResult in
            switch encodingResult.result {
                case .success(let value):
                    let json = JSON(value).description
                XMLogger.netInfo(json)
                    if let dict = value as? [String : AnyObject]{
                        guard var data = JSONDeserializer<ResponseModel<T>>.deserializeFrom(dict: dict) else {
                            var rs = ResponseModel<T>()
                            rs.code = .netBad
                            rs.message = "App解析出错"
                            rs.realResp = value
                            callBack(rs)
                            return}
                        data.realResp = value
                        callBack(data)
                    } else {
                        var rs = ResponseModel<T>()
                        rs.code = .netBad
                        rs.message = "App解析出错"
                        rs.realResp = value
                        callBack(rs)
                    }
                    break
                case .failure(let error):
                XMLogger.netInfo("请求结果：------->\(String(describing: wholeUrl))\n")
                XMLogger.netInfo(error)
                    callBack(self.badResponse(realResp: error.errorDescription, message: error.errorDescription ?? ""))
                    break
            }
        }
        return reqest
    }


    func getDictionaryFromJSONString(jsonString:String) ->NSDictionary{
        let jsonData:Data = jsonString.data(using: .utf8)!
        let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
        if dict != nil {
            return dict as! NSDictionary
        }
        return NSDictionary()
    }
    
    //MARK:网络监听
    func setUpNetLister() {
        netAbility?.startListening(onUpdatePerforming: { [weak self] status in
            switch status {
                case .unknown:
                    self?.netStauts.onNext(.unkown)
                case .notReachable:
                    self?.netStauts.onNext(.notReachable)
                case .reachable(.cellular):
                    self?.netStauts.onNext(.WWAN)
                case .reachable(.ethernetOrWiFi):
                    self?.netStauts.onNext(.WIFI)
            }
        })
    }
}
